# coding: utf-8

import os
import sys
import json
import time
import pycurl
import urllib2
import requests

from StringIO import StringIO

'''
API介绍:
GPD服务提供四个接口, 增删改查, 操作数据存在MongoDB中.
比如可以设置json某个路径下的一组值, 详细见下方代add, update, del等函数.

功能测试:
配合jktest.py标注接口功能用例(返回结果检查点), 可以很快实现回归.
当前脚本只演示性能, 没有做功能用例的标注.

性能测试:
语境中心API, 在UAT环境, 使用pycurl单线程循环请求, 查询接口的QPS可以到1500+
使用ccreq的10并发, QPS可以到10,000+, 基本和 JMeter 压测结果一致.
如果使用requests方式请求, QPS会下降很多, 这也是pycurl别request的性能区别.

稳定性测试参考stab.sh

'''

AppKey = "3dcddlnx7ddlb2xatjxtbtxha6xah7iogajzkqie"
Client_Info_Map = {
            "productLine": "productLine_dakang_test",
            "udid": "Client_Info_Map_Udid",
            "appKey": AppKey,
        }
Action_RequestId = "Action_RequestId"

def perf_pycurl():
    '''通过while的时间点, 进行循环压测, 也可以随意指定think_time'''
    total = 0
    pass_ = 0
    tid = '000'
    log = 'log.log'

    duration = 3
    if len(sys.argv) >= 3:
        tid = sys.argv[1]
        duration = int(sys.argv[2])

    print "thread %s will run %d(s)" % (tid, duration)

    c = pycurl.Curl()
    _id = "JUnit-test-collect-info-00000"
    url = "http://%s/GPDService/v2/query" % GPD
    params = {
        "clientInfo": {
            "productLine": "test01",
            "udid": "test02",
            "appKey": "test03"
        },
        "actionRequestId":"1111111111111",
        "action": {
            "domain": domain,
            "id": _id,
            "path": "baseMap_Udid",
            # "path": "dstServiceProfile.enjoyMusic.serviceInfo.musicList"
        }
    }
    data = json.dumps(params)
    c.setopt(pycurl.URL, url)
    c.setopt(pycurl.HTTPHEADER, ['Accept: application/json'])
    c.setopt(pycurl.POST, 1)
    c.setopt(pycurl.POSTFIELDS, data)
    buff = StringIO()
    expect = '"id":"%s"' % _id
    begin = time.time()
    while time.time() < begin + duration:
        c.setopt(c.WRITEFUNCTION, buff.write)
        c.perform()
        ret = buff.getvalue()
        buff.truncate(0)
        if expect in ret:
            pass_ += 1
        total += 1

    c.close()
    dur = (time.time() - begin)
    tps = pass_ / dur
    resp_time = dur / pass_
    result = '\nthread: %s: total: %d, pass: %d, TPS: %.2f, resp_time: %.4f, \
elapsed_time: %.2f\n' %(tid, total, pass_, tps, resp_time, dur)
    print result.strip()
    with open(log, 'a') as log:
        log.write(result)

def perf_test():
    total = 0
    pass_ = 0
    tid = '000'
    log = 'log.log'

    duration = 3
    if len(sys.argv) >= 3:
        tid = sys.argv[1]
        duration = int(sys.argv[2])

    print "thread %s will run %d(s)" % (tid, duration)

    # add_id = 'update_test_%s_%.4f' % (tid, time.time())
    # ret = add(_id=add_id, tid=tid)
    # print "add_id: %s" % add_id
    begin = time.time()
    while time.time() < begin + duration:
        ############################# ADD
        # ret = add(tid=tid)
        # if '' in ret:
        #     pass_ += 1
        ############################# QUERY
        _id = "JUnit-test-collect-info-00000"
        path = 'baseMap_Udid.myage'
        ret = query(_id, path)
        print ret
        expect = '"id":"%s"' % _id
        if expect in ret:
            pass_ += 1
        else:
            print ">>>>>>> ", ret
        # pass_ += 1
        total += 1
        ############################# UPDATE
        # ret = update(_id=add_id, path='', value={'update': 'test', 'time': time.time()})
        # print ret
        # if '' in ret:
        #     pass_ += 1
        ############################# Add && DELETE
        # add_del_id = 'delete_test_%s_%.4f' % (tid, time.time())
        # print add_del_id
        # ret = add(_id=add_del_id, tid=tid)
        # total += 1
        # if '' in ret:
        #     pass_ += 1

        # ret = delete(_id=add_del_id)
        # total += 1
        # if '' in ret:
        #     pass_ += 1

    dur = (time.time() - begin)
    tps = pass_ / dur
    resp_time = dur / pass_
    result = '\nthread: %s: total: %d, pass: %d, TPS: %.2f, resp_time: %.4f, \
elapsed_time: %.2f\n' %(tid, total, pass_, tps, resp_time, dur)
    print result.strip()
    with open(log, 'a') as log:
        log.write(result)

def stab_test():
    ''' ADD QUERY UPDATE DELTE One by One'''
    total = 0
    pass_ = 0
    tid = '000'
    log = 'log.log'

    duration = 3
    if len(sys.argv) >= 3:
        tid = sys.argv[1]
        duration = int(sys.argv[2])

    print "thread %s will run %d(s)" % (tid, duration)

    success = '"code":200,"msg":"success","version":"v2"'
    value = {"name": "小可爱", "age": "3"}
    
    begin = time.time()
    while time.time() < begin + duration:
        
        _id = 'stab_test_id_%s_%.4f' % (tid, time.time())
        path = 'stab_test_path_%s_%.4f' % (tid, time.time())
        ############################# ADD
        ret = add(_id, path, value)
        total += 1
        if success in ret:
            pass_ += 1
        ############################# QUERY
        ret = query(_id, path)
        expect = '"udid":"%s"' % _id
        if expect in ret:
            pass_ += 1
        ############################# UPDATE
        value["update"] = "test"
        ret = update(_id, path, value)
        if success in ret:
            pass_ += 1
        ############################# DELETE
        ret = delete(_id, '')
        total += 1
        if success in ret:
            pass_ += 1
        # print _id
        # time.sleep(2)

    dur = (time.time() - begin)
    tps = pass_ / dur
    resp_time = dur / pass_
    result = '\nthread: %s: total: %d, pass: %d, TPS: %.2f, resp_time: %.4f, \
elapsed_time: %.2f\n' %(tid, total, pass_, tps, resp_time, dur)
    print result.strip()
    with open(log, 'a') as log:
        log.write(result)

def _send_request_post(url, params):
    header = {"Connection": "close", "Content-Type": "application/json"}
    req = requests.post(url, data=json.dumps(params), headers=header)
    ret = req.content
    return ret

def _send_urllib_post(url, params):
    header = {"Connection": "close", "Content-Type": "application/json"}
    data = json.dumps(params)
    req = urllib2.Request(url, data, header)
    f = urllib2.urlopen(req)
    response = f.read()
    f.close()
    req = requests.post(url, data=json.dumps(params), headers=header)
    ret = req.content
    return ret

def __init__pycurl():
    c = pycurl.Curl()
    buffer = StringIO()

    data = json.dumps(params)
    c.setopt(pycurl.URL, url)
    c.setopt(pycurl.HTTPHEADER, ['Accept: application/json'])
    c.setopt(pycurl.POST, 1)
    c.setopt(pycurl.POSTFIELDS, data)
    # c.setopt(c.WRITEDATA, buffer)
    c.setopt(c.WRITEFUNCTION, buffer.write)

def _send_post(url, params):
    c = pycurl.Curl()
    buffer = StringIO()

    data = json.dumps(params)
    c.setopt(pycurl.URL, url)
    c.setopt(pycurl.HTTPHEADER, ['Accept: application/json'])
    c.setopt(pycurl.POST, 1)
    c.setopt(pycurl.POSTFIELDS, data)
    # c.setopt(c.WRITEDATA, buffer)
    c.setopt(c.WRITEFUNCTION, buffer.write)
    # c.setopt(pycurl.VERBOSE, 1)
    c.perform()
    # print curl_agent.getinfo(pycurl.RESPONSE_CODE)
    c.close()
    body = buffer.getvalue()
    return body

def _send_get(url):
    return urllib2.urlopen(url).read()

def add(_id, path, value):
    url = "http://%s/GPDService/v2/add" % GPD
    params = {
        "clientInfo": Client_Info_Map,
        "actionRequestId": Action_RequestId,
        "action": {
            "id": _id,
            "domain": domain, # user, udid, service, public
            "path": path,
            "value" : value,
        }
    }

    ret = _send_post(url, params)
    return ret

def query(_id, path):
    url = "http://%s/GPDService/v2/query" % GPD
    params = {
        "clientInfo": Client_Info_Map,
        "actionRequestId": Action_RequestId,
        "action": {
            "domain": domain,
            "id": _id,
            "path": path
        }
    }
    # ret = _send_post(url, params)
    ret = _send_request_post(url, params)
    return ret

def query_multiple(actions):
    url = "http://%s/GPDService/v2/query" % GPD
    params = {
        "clientInfo": Client_Info_Map,
        "actionRequestId": Action_RequestId,
        "actions": actions
    }
    print url
    print params

    ret = _send_post(url, params)
    return ret

def update(_id, path, value):
    url = "http://%s/GPDService/v2/update" % GPD
    params = {
        "clientInfo": Client_Info_Map,
        "actionRequestId": Action_RequestId,
        "action": {
            "domain": domain,
            "id": _id,
            "path": path,
            "value": value,
        }
    }
    ret = _send_post(url, params)
    return ret

def add_mass(num=100):
    ''' udid = "delete_test_%d" '''
    print "add %d0000 udid ..." % num
    for i in range(num*10000):
        udid = "delete_test_%d" % i
        add(_id=udid, path='', value='', tid='000')

def delete(_id, path):
    url = "http://%s/GPDService/v2/delete" % GPD
    params = {
        "clientInfo": Client_Info_Map,
        "actionRequestId": Action_RequestId,
        "action": {
            "domain": domain,
            "id": _id,
            "path": path,
        }
    }
    ret = _send_post(url, params)
    return ret

def get_version(server):
    url = "http://%s/GPDService/manager/version" % GPD
    if server == DC:
        url = "http://%s/athenaProfile/manager/version" % DC

    return _send_get(url)

def get_status(server):
    url = "http://%s/GPDService/manager/status" % GPD
    if server == DC:
        url = "http://%s/athenaProfile/manager/status" % DC

    return _send_get(url)


if __name__ == '__main__':
    """
    action、actions、clientInfo、domain、id都不能为空
    add和update操作，path不能为空
    不支持批量操作
    """
    GPD = "172.18.10.45:8080"
    DC = "172.18.10.146:8080"

    domain = "udid"

    _id = "JUnit-test-collect-info-00000"

    path = 'baseMap_Udid.myage'
    value = {
        "imgUrl": "http://img.xiami.net/images/album/img70/1970/329341377838236_1.jpg",
        "duration": 260,
    }
    
    ####################################################################
    print add(_id, path, value)
    print query(_id, path)
    print update(_id, path, value)
    print delete(_id, '')

    actions = [{
        "domain": "udid",
        "id": "krc_chat_new.txt-1067-1476",
        "path": "baseMap_Udid"
        },
        {
        "domain": "udid",
        "id": "krc_chat.txt-1386-1386",
        "path": "baseMap_Udid"
        }]

    perf_test()  # requests方式
    # perf_pycurl()
    # stab_test()

